﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WordNet.Core.ElementContracts;
using WordNet.Core.Relations;

namespace WordNet.Core
{
    public class LexicalRelationTracer: ILexicalRelations
    {
        private IWNDictionary _dictionary;

        public LexicalRelationTracer(IWNDictionary dic)
        {
            _dictionary = dic;
        }

        public IWordNode Find(IWord word, Pointer pointer)
        {
            if (word == null || pointer == null)
                throw new ArgumentNullException("parameters cannot be null");
            
            if (pointer == Pointer.ANTONYM)
                return FindAntonym(word);
            else if (pointer == Pointer.DERIVED_FROM_ADJ)
                return FindDerived(word);
            else if (pointer == Pointer.PERTAINYM)
                return FindPertainym(word);
            else if (pointer == Pointer.PARTICIPLE)
                return FindParticiple(word);
            else
                throw new ArgumentException("wrong pointer");
        }

        public IAntonym FindAntonym(IWord word)
        {
            if (word == null)
                throw new ArgumentNullException();

            var relatedWords = word.GetRelatedWords(Pointer.ANTONYM);
            
            IAntonym wordNode = null;
            if (relatedWords == null)
            {
                if (word.Synset.IsAdjectiveSatellite)
                {
                    foreach (var id in word.Synset.GetRelatedSynsets())
                    {
                        var viaWord = _dictionary.GetSynset(id);
                        var wr = viaWord.GetWords().Find(w => w.GetRelatedMap().ContainsKey(Pointer.ANTONYM));
                        if (wr != null)
                        {
                            var awi = wr.GetRelatedWords(Pointer.ANTONYM); 
                            wordNode = new AntonymNode(word);
                            wordNode.Antonym = new AntonymNode(_dictionary.GetWord(awi[0]));
                            wordNode.Indirect = wr;
                            break;
                        }
                    }
                }
            }
            else
            {
                if (relatedWords.Count > 1)
                    throw new InvalidOperationException();
                wordNode = new AntonymNode(word);
                var relatedWord = relatedWords[0];
                var antonym = _dictionary.GetWord(relatedWord);
                var antNode = new AntonymNode(antonym);
                if (antonym.Synset.IsAdjectiveHead)
                {
                    foreach (var rs in antonym.Synset.GetRelatedSynsets())
                    {
                        var syns = _dictionary.GetSynset(rs);
                        if (syns.IsAdjectiveSatellite)
                        {
                            antNode.AddRelatedSynsets(syns);
                        }
                    }
                }
                wordNode.Antonym = antNode;
            }
            return wordNode;
        }

        public IDerived FindDerived(IWord word)
        {
            if (word == null)
                throw new ArgumentNullException();
            
            if (word.PartOfSpeech != POS.ADVERB)
                throw new ArgumentException();

            IDerived derived = null;
            var relatedWord = word.GetRelatedWords(Pointer.DERIVED_FROM_ADJ);
            if (relatedWord != null)
            {
                derived = new DerivedNode(word);
                derived.DerivedFrom = _dictionary.GetWord(relatedWord[0]);
            }
            
            return  derived;
        }

        public IParticiple FindParticiple(IWord word)
        {
            if (word == null)
                throw new ArgumentNullException();
            if (word.PartOfSpeech != POS.ADJECTIVE)
                throw new ArgumentException();
           
            IParticiple participle = null;
            var relatedWord = word.GetRelatedWords(Pointer.PARTICIPLE);
            if (relatedWord != null)
            {
                participle = new ParticipleNode(word);
                participle.DerivedFrom = _dictionary.GetWord(relatedWord[0]);
            }
             
            return participle;
        }

        public IPertainym FindPertainym(IWord word)
        {
            if (word == null)
                throw new ArgumentNullException();
            if (word.PartOfSpeech != POS.ADJECTIVE)
                throw new ArgumentException();

            IPertainym pertainym = null;
            var relatedWord = word.GetRelatedWords(Pointer.PERTAINYM);
            if (relatedWord != null)
            {
                pertainym = new PertainymNode(word);
                pertainym.PertainsTo = _dictionary.GetWord(relatedWord[0]);
            }
            
            return pertainym ;
        }
    }
}
